﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using WeChatSDK.Common;
using WeChatSDK.Common.Enums.Http;
using WeChatSDK.WeChatDto.ErrorMessage;
using WeChatSDK.WeChatDto.Request.Http;

namespace WeChatSDK.RequestComponent.Http
{
    /// <summary>
    /// Http请求处理
    /// </summary>
    public class HttpHandle
    {
        #region HttpClient
        #region 设置HttpRequestMessage
        private HttpRequestMessage SetHttpRequestMessage(HttpRequestDto httpRequestDto, HttpClient httpClient)
        {
            if (httpRequestDto.Url.Contains("https"))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            }
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage();
            httpRequestMessage.Content = this.SetHttpContent(httpRequestDto, httpClient);
            httpRequestMessage.Method = new HttpMethod(httpRequestDto.Method.ToString());
            httpRequestMessage.RequestUri = new Uri(httpRequestDto.Url);
            httpRequestMessage.Version = new Version("1.1");
            return httpRequestMessage;
        }
        #endregion

        #region 检查证书结果
        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }
        #endregion

        #region 设置HttpContent
        /// <summary>
        /// 设置HttpContent
        /// </summary>
        /// <param name="httpRequestDto">Http请求对象</param>
        private HttpContent SetHttpContent(HttpRequestDto httpRequestDto, HttpClient httpClient)
        {

            if (httpRequestDto.Method == MethodType.POST || httpRequestDto.Method == MethodType.PUT || httpRequestDto.Method == MethodType.OPTIONS)
            {
                if (httpRequestDto.ContentType == FormatType.FormData)
                {
                    string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
                    httpClient.DefaultRequestHeaders.Add("User-Agent", "KnowledgeCenter");
                    httpClient.DefaultRequestHeaders.Remove("Expect");
                    httpClient.DefaultRequestHeaders.Remove("Connection");
                    httpClient.DefaultRequestHeaders.ExpectContinue = false;
                    httpClient.DefaultRequestHeaders.ConnectionClose = true;
                    MultipartFormDataContent content = new MultipartFormDataContent(boundary);
                    content.Headers.Remove("Content-Type");
                    content.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary);
                    ByteArrayContent byteArrayContent = new ByteArrayContent(File.ReadAllBytes(Encoding.UTF8.GetString(httpRequestDto.Content)));
                    content.Add(byteArrayContent);
                    byteArrayContent.Headers.Remove("Content-Disposition");
                    byteArrayContent.Headers.TryAddWithoutValidation("Content-Disposition", "form-data; name=\"media\";filename=\"" + httpRequestDto.Headers["filename"] + "\"" + "");
                    byteArrayContent.Headers.Remove("Content-Type");
                    byteArrayContent.Headers.TryAddWithoutValidation("Content-Type", httpRequestDto.Headers["Content-Type"]);
                    return content;
                }
                else
                {
                    StringContent content = new StringContent(Encoding.UTF8.GetString(httpRequestDto.Content));
                    switch (httpRequestDto.ContentType)
                    {
                        case FormatType.JSON:
                            content.Headers.ContentType = new MediaTypeHeaderValue("application/json") { CharSet = "utf-8" };
                            break;
                        case FormatType.XML:
                            content.Headers.ContentType = new MediaTypeHeaderValue("application/xml") { CharSet = "utf-8" };
                            break;
                        case FormatType.RAW:
                            content.Headers.ContentType = new MediaTypeHeaderValue("application/text") { CharSet = "utf-8" };
                            break;
                    }
                    return content;
                }
            }
            else
            {
                StringContent content = new StringContent("");
                return content;
            }
        }

        /// <summary>
        /// 发送Http请求
        /// </summary>
        /// <param name="httpRequestDto">http请求对象</param>
        /// <returns></returns>
        public HttpResponseDto HttpSendRequest(HttpRequestDto httpRequestDto)
        {

            HttpClient httpClient = new HttpClient();
            HttpResponseMessage response = null;
            try
            {
                response = httpClient.SendAsync(this.SetHttpRequestMessage(httpRequestDto, httpClient)).GetAwaiter().GetResult();
            }
            catch (HttpRequestException ex)
            {
                response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.BadRequest;
#if DEBUG
                response.Content = new StringContent(ex.Message);
#else
                response.Content = new StringContent("网络异常，请重试！");
#endif
            }
            HttpResponseDto httpResponseDto = new HttpResponseDto();
            if (response.IsSuccessStatusCode)
            {
                httpResponseDto.ResponseMessage = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

                if (httpResponseDto.ResponseMessage.Contains("errcode"))
                {
                    WeChatErrorMessageDto errorMessageDto = JsonConvert.DeserializeObject<WeChatErrorMessageDto>(httpResponseDto.ResponseMessage);
                    if (errorMessageDto.ErrCode == 0)
                    {
                        httpResponseDto.IsError = false;
                    }
                    else
                    {
                        httpResponseDto.IsError = true;
                        httpResponseDto.ResponseMessage = GetErrMessage(errorMessageDto);
                    }
                }
                else
                {
                    httpResponseDto.IsError = false;
                }
            }
            else
            {
                httpResponseDto.IsError = true;
                httpResponseDto.ResponseMessage = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                Log(httpResponseDto.ResponseMessage);

                WeChatErrorMessageDto errorMessageDto = JsonConvert.DeserializeObject<WeChatErrorMessageDto>(httpResponseDto.ResponseMessage);
                httpResponseDto.ResponseMessage = GetErrMessage(errorMessageDto);
            }
            return httpResponseDto;

        }
        #endregion
        private void Log(string response)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());

            FileInfo fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, "wechatSDKHttpRequestLog.txt").ToString());

            if (!fileInfo.Exists)
            {
                using (StreamWriter sw = fileInfo.CreateText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    sw.WriteLine("Response:{0}", response);
                    sw.WriteLine();
                }
            }
            else
            {
                using (StreamWriter sw = fileInfo.AppendText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    sw.WriteLine("Response:{0}", response);
                    sw.WriteLine();
                }
            }
        }
        #region WebClient
        /// <summary>
        /// 发送JSON数据的POST请求
        /// </summary>
        /// <param name="httpRequestDto">http请求对象</param>
        /// <returns></returns>
        public HttpResponseDto WebSendRequest(HttpRequestDto httpRequestDto)
        {
            using (WebClient webClient = new WebClient())
            {
                foreach (KeyValuePair<string, string> header in httpRequestDto.Headers)
                {
                    webClient.Headers.Add(header.Key, header.Value);
                }
                byte[] response;
                if (httpRequestDto.Method == MethodType.POST || httpRequestDto.Method == MethodType.PUT)
                {
                    if (httpRequestDto.ContentType == FormatType.FormData)
                    {
                        response = webClient.UploadFile(httpRequestDto.Url, httpRequestDto.Method.ToString(), Encoding.UTF8.GetString(httpRequestDto.Content));
                    }
                    else
                    {
                        response = webClient.UploadData(new Uri(httpRequestDto.Url), MethodType.POST.ToString(), httpRequestDto.Content);
                    }
                }
                else
                {
                    response = webClient.DownloadData(new Uri(httpRequestDto.Url));
                }
                HttpResponseDto httpResponseDto = new HttpResponseDto();
                if (webClient.ResponseHeaders.AllKeys.Any(p => p.Equals("Content-Type")))
                {
                    string contentType = webClient.ResponseHeaders.Get("Content-Type");
                    httpResponseDto.ResponseMessage = Encoding.UTF8.GetString(response);
                    if (httpResponseDto.ResponseMessage.Contains("errcode"))
                    {
                        WeChatErrorMessageDto errorMessageDto = JsonConvert.DeserializeObject<WeChatErrorMessageDto>(httpResponseDto.ResponseMessage);
                        if (errorMessageDto.ErrCode == 0)
                        {
                            httpResponseDto.IsError = false;
                        }
                        else
                        {
                            httpResponseDto.IsError = true;
                            httpResponseDto.ResponseMessage = GetErrMessage(errorMessageDto);
                        }
                    }
                    else
                    {
                        httpResponseDto.IsError = false;
                    }
                }
                else
                {
                    httpResponseDto.ResponseData = response;
                    httpResponseDto.IsError = false;
                }
                return httpResponseDto;
            }
        }
        #endregion

        public string GetErrMessage(WeChatErrorMessageDto weChatErrorMessageDto)
        {
            if (WeChatGeneral.ErrorMessage.Any(p => p.Key == weChatErrorMessageDto.ErrCode.ToString()))
            {
                return WeChatGeneral.ErrorMessage[weChatErrorMessageDto.ErrCode.ToString()];
            }
            else
            {
                return weChatErrorMessageDto.ErrMsg;
            }
        }
        #endregion

    }
}
